Risk analysis

By Evgenia "Jenny" Nitishinskaya and Delaney Granizo-Mackenzie

Notebook released under the Creative Commons Attribution 4.0 License.


We can use factor models to analyze the sources of risks and returns in portfolios. Recall that a factor model expresses the returns as

$$R_i = a_i + b_{i1} F_1 + b_{i2} F_2 + \ldots + b_{iK} F_K + \epsilon_i$$

By modelling the historical returns, we can see how much of them is due to speculation on different factors and how much to asset-specific fluctuations ($\epsilon_p$). We can also examine what sources of risk the portfolio is exposed to. In risk analysis, we often model active returns (returns relative to a benchmark) and active risk (standard deviation of active returns, also known as tracking error or tracking risk).

For instance, we can find a factor's marginal contribution to active risk squared (FMCAR). For factor $j$, this is

$$ \text{FMCAR}_j = \frac{b_j^a \sum_{i=1}^K b_i^a Cov(F_j, F_i)}{(\text{Active risk})^2} $$

where $b_i^a$ is the portfolio's active exposure (exposure different from the benchmark's) to factor $i$. This tells us how much risk we incur by being exposed to factor $j$, given all the other factors we're already exposed to.

Fundamental factor models are often used to evaluate portfolios because they correspond directly to investment choices (e.g. whether we invest in small-cap or large-cap stocks, etc.). Below, we construct a model to evaluate a single asset; for more information on the model construction, check out the fundamental factor models notebook.


In [2]:
# Import the libraries we'll be using
import numpy as np
import statsmodels.api as sm
from statsmodels import regression
import matplotlib.pyplot as plt

# Get market cap and book-to-price for all assets in universe
fundamentals = init_fundamentals()
data = get_fundamentals(query(fundamentals.valuation.market_cap,
                              fundamentals.valuation_ratios.book_value_yield), '2015-07-31').T

# Drop missing data
data.dropna(inplace=True)

# Following the Fama-French model, ignore assets with negative book-to-price
data = data.loc[data['book_value_yield'] > 0]

In [4]:
# As per Fama-French, get the top 30% and bottom 30% of stocks by market cap
market_cap_top = data.sort('market_cap')[7*len(data)/10:]
market_cap_bottom = data.sort('market_cap')[:3*len(data)/10]

# Factor 1 is returns on portfolio that is long the top stocks and short the bottom stocks
f1 = (np.mean(get_pricing(market_cap_top.index, fields='price',
                          start_date='2014-07-31', end_date='2015-07-31').pct_change()[1:].T.dropna()) -
      np.mean(get_pricing(market_cap_bottom.index, fields='price',
                          start_date='2014-07-31', end_date='2015-07-31').pct_change()[1:].T.dropna()))

# Repeat above procedure for book-to-price
bp_top = data.sort('book_value_yield')[7*len(data)/10:]
bp_bottom = data.sort('book_value_yield')[:3*len(data)/10]

f2 = (np.mean(get_pricing(bp_top.index, fields='price',
                          start_date='2014-07-31', end_date='2015-07-31').pct_change()[1:].T.dropna()) -
      np.mean(get_pricing(bp_bottom.index, fields='price',
                          start_date='2014-07-31', end_date='2015-07-31').pct_change()[1:].T.dropna()))

Now that we have our factors, we will use them to model active returns (that is, asset returns less benchmark returns):


In [24]:
# Get returns data for our asset
asset = get_pricing('HSC', fields='price', start_date='2014-07-31', end_date='2015-07-31').pct_change()[1:]
bench = get_pricing('SPY', fields='price', start_date='2014-07-31', end_date='2015-07-31').pct_change()[1:]
active = asset - bench

In [29]:
# Perform linear regression to get the coefficients in the model
b1, b2 = regression.linear_model.OLS(active, sm.add_constant(np.column_stack((f1, f2)))).fit().params[1:]

# Print the coefficients from the linear regression
print 'Sensitivities of active returns to factors:\nMarket cap: %f\nB/P: %f' %  (b1, b2)


Sensitivities of active returns to factors:
Market cap: 0.031546
B/P: 0.764279

Using the formula above, we compute the factors' marginal contributions to active risk squared:


In [27]:
cov = np.cov(f1, f2)
ar_squared = (active.std())**2
fmcar1 = (b1*(b2*cov[0,1] + b1*cov[0,0]))/ar_squared
fmcar2 = (b2*(b1*cov[0,1] + b2*cov[1,1]))/ar_squared
print 'FMCAR_1:', fmcar1
print 'FMCAR_2:', fmcar2


FMCAR_1: -0.000743366226964
FMCAR_2: 0.0622232250229

The first factor has a small negative contribution to active risk squared, while the second accounts for about 6.2% of that risk. The rest can be attributed to active specific risk, i.e. factors that we did not take into account or the asset's idiosyncratic risk.

Factor and tracking portfolios

We can use factor and tracking portfolios to tweak a portfolio's sensitivities to different sources of risk.

A factor portfolio has a sensitivity of 1 to a particular factor and 0 to all other factors. In other words, it represents the risk of that one factor. We can add a factor portfolio to a larger portfolio to adjust its exposure to that factor.

A similar concept is a tracking portfolio, which is constructed to have the same factor sensitivities as a benchmark or other portfolio. Like a factor portfolio, this allows us to either speculate on or hedge out the risks associated with that benchmark or portfolio. For instance, we regularly hedge out the market, because we care about how our portfolio performs relative to the market, and we don't want to be subject to the market's fluctuations.

To construct a factor or tracking portfolio, we need the factor sensitivities of what we want to track. We already know what these are in the former case, but we need to compute them in the latter using usual factor model methods. Then, we pick some $K+1$ assets (where $K$ is the number of factors we're considering) and solve for the weights of the assets in the portfolio.

Example

Say we have two factors $F_1$ and $F_2$, and a benchmark with sensitivities of 1 and 1.1 to the factors, respectively. We identify 3 securities $x_1, x_2, x_3$ that we would like to use in composing a portfolio that tracks the benchmark, whose sensitivities are $b_{11} = 0.7$, $b_{12} = 1.1$, $b_{21} = 0.1$, $b_{22} = 0.5$, $b_{31} = 1.5$, $b_{32} = 1.3$. We would like to compute weights $w_1$, $w_2$, $w_3$ so that our tracking portfolio is

$$ P = w_1 x_1 + w_2 x_2 + w_3 x_3 $$

We want our portfolio sensitivities to match the benchmark:

$$ w_1 b_{11} + w_2 b_{21} + w_3 b_{31} = 1 $$$$ w_1 b_{12} + w_2 b_{22} + w_3 b_{32} = 1.1 $$

Also, the weights need to sum to 1:

$$ w_1 + w_2 + w_3 = 1 $$

Solving this system of 3 linear equations, we find that $w_1 = 1/3$, $w_2 = 1/6$, and $w_3 = 1/2$. Putting the securities together into a portfolio using these weights, we obtain a portfolio with the same risk profile as the benchmark.